package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.apis.article.IArticleClient;
import com.heima.apis.user.IUserClient;
import com.heima.comment.pojos.ApComment;
import com.heima.comment.pojos.ApCommentLike;
import com.heima.comment.pojos.CommentVo;
import com.heima.comment.service.CommentService;
import com.heima.common.constants.HotArticleConstants;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.comment.dto.CommentDto;
import com.heima.model.comment.dto.CommentLikeDto;
import com.heima.model.comment.dto.CommentSaveDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.UpdateArticleMess;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.thread.AppThreadLocalUtil;
import com.mongodb.client.result.UpdateResult;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class CommentServiceImpl implements CommentService {

    private final IArticleClient articleClient;

    private final IUserClient userClient;

    private final MongoTemplate mongoTemplate;

    private final KafkaTemplate<String, String> kafkaTemplate;
    /**
     * 保存评论
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveComment(CommentSaveDto dto) {
        //1.参数校验
        if (dto == null || dto.getArticleId() == null || dto.getArticleId()<1 ||StringUtils.isBlank(dto.getContent())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //校验文章是否可以评论
        if(!checkParams(dto.getArticleId())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"该文章评论权限已关闭");
        }
        if (dto.getContent().length()> 140){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"评论内容不能超过140字");
        }
        //2.判断是否登录
        ApUser user = AppThreadLocalUtil.getUser();
        if (user == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_ADMIND);
        }
        //3.安全检查 自行实现
        //4.保存评论
        ApUser apUser = userClient.findUserById(user.getId());
        if (apUser == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"用户信息有误");
        }
        ApComment apComment = ApComment.builder()
                .authorId(user.getId())
                .authorName(apUser.getName())
                .entryId(dto.getArticleId())
                .type((short) 0)
                .content(dto.getContent())
                .image(apUser.getImage())
                .createdTime(new Date())
                .likes(0)
                .reply(0)
                .flag((short) 0)
                .build();
        mongoTemplate.save(apComment);

        //发送消息，进行聚合
        UpdateArticleMess mess = new UpdateArticleMess();
        mess.setArticleId(dto.getArticleId());
        mess.setType(UpdateArticleMess.UpdateArticleType.COMMENT);
        mess.setAdd(1);
        kafkaTemplate.send(HotArticleConstants.HOT_ARTICLE_SCORE_TOPIC, JSON.toJSONString(mess));
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
    /**
     * 校验文章是否可以评论
     * @param articleId
     * @return
     */
    private boolean checkParams(Long articleId) {
        //是否可以评论
        ResponseResult result = articleClient.findArticleConfigByArticleId(articleId);
        if (!result.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode()) || result.getData() == null){
            return false;
        }
        ApArticleConfig apArticleConfig = JSON.parseObject(JSON.toJSONString(result.getData()), ApArticleConfig.class);
        return apArticleConfig != null && apArticleConfig.getIsComment();
    }
    /**
     * 评论点赞
     * @param dto
     * @return
     */
    @Override
    public ResponseResult like(CommentLikeDto dto) {
        //1.检查参数
        if (dto ==null || dto.getCommentId() ==null || dto.getOperation() == null || dto.getOperation() < 0 || dto.getOperation() > 1){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.判断是否登录
        ApUser user = AppThreadLocalUtil.getUser();
        if (user == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //构造查询条件
        Update update = new Update().inc("likes", dto.getOperation() == 0 ? 1 : -1);
        Query commentQuery = Query.query(Criteria.where("_id").is(dto.getCommentId()));
        //3.点赞
        if (dto.getOperation() == 0){
            //更新评论点赞数量
            UpdateResult updateResult = mongoTemplate.updateFirst(commentQuery, update, ApComment.class);
            if (updateResult.getModifiedCount() ==0){
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "点赞失败");
            }
            //保存评论点赞数据
            ApCommentLike apCommentLike = ApCommentLike.builder()
                    .commentId(dto.getCommentId())
                    .authorId(user.getId())
                    .build();
            mongoTemplate.save(apCommentLike);
        } else if (dto.getOperation() == 1){
            //更新评论点赞数量
            UpdateResult updateResult = mongoTemplate.updateFirst(commentQuery, update, ApComment.class);
            if (updateResult.getModifiedCount() ==0){
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "取消点赞失败");
            }
            //删除评论点赞数据
            Query query = Query.query(Criteria.where("commentId").is(dto.getCommentId()).and("authorId").is(user.getId()));
            mongoTemplate.remove(query);
        }

        //4.返回结果
        ApComment apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
        Map<String, Object>result = new HashMap<>();
        if (apComment != null) {
            result.put("likes", apComment.getLikes());
        }
        return ResponseResult.okResult(result);
    }

    /**
     * 评论分页查询
     * @param dto
     * @return
     */
    @Override
    public ResponseResult load(CommentDto dto) {
        //1.检查参数
        if (dto ==null || dto.getArticleId() ==null || dto.getArticleId() <1){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.加载数据
        Query query = Query.query(Criteria.where("entryId").is(dto.getArticleId()).and("createdTime").lt(dto.getMinDate()));
        query.with(Sort.by(Sort.Direction.DESC, "createdTime"));
        List<ApComment> apComments = mongoTemplate.find(query, ApComment.class);
        //3.数据封装返回
        //3.1 用户未登录
        ApUser user = AppThreadLocalUtil.getUser();
        if (user == null){
            return ResponseResult.okResult(apComments);
        }
        //3.2 用户已登录
        //需要查询当前评论中哪些数据被点赞了
        List<String> idList = apComments.stream().map(ApComment::getId).collect(Collectors.toList());
        Query query1 = Query.query(Criteria.where("commentId").in(idList).and("authorId").is(user.getId()));
        List<ApCommentLike> apCommentLikes = mongoTemplate.find(query1, ApCommentLike.class);
        if (apCommentLikes.isEmpty()){
            return ResponseResult.okResult(apComments);
        }
        //封装Vo
        List<CommentVo> resultList = new ArrayList<>();
        for (ApComment apComment : apComments) {
            CommentVo commentVo = new CommentVo();
            BeanUtils.copyProperties(apComment,commentVo);
            for (ApCommentLike apCommentLike : apCommentLikes) {
                if (apCommentLike.getCommentId().equals(apComment.getId())){
                    commentVo.setOperation((short) 0);
                }
            }
            resultList.add(commentVo);
        }
        return ResponseResult.okResult(resultList);
    }
}
